package com.example.proxy.aspect;

import com.example.proxy.annotation.Log;
import com.example.proxy.annotation.LogCopy;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @Description : 通知类型的使用及两种切点写法
 * @Author : Bruce Lee
 * @CreateTime : 2024/4/10
 */

@Aspect
@Component
@Slf4j
public class LogAspect {

    /**
     * 拦截带有@Log注解及@LogCopy注解的方法
     * 但切面方法中无法直接访问注解实例及其属性值，只能通过额外的反射获取
     * @param joinPoint
     * @param result
     */
    @AfterReturning(pointcut = "@annotation(com.example.proxy.annotation.Log) && @annotation(com.example.proxy.annotation.LogCopy)", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result){
        log.info("方法返回值：{}", result);
        log.info("方法名：{}", joinPoint.getSignature().getName());
    }




    /**
     * 拦截同时带有@Log和@LogCopy注解的方法
     * 但与上述不同在于：Spring AOP会在方法执行时，自动将对应注解实例注入到参数中
     * 所以，切面方法可以直接访问注解相关属性
     * @param joinPoint
     * @param result
     * @param controllerLog
     * @param controllerLogCopy
     */
    @AfterReturning(pointcut = "@annotation(controllerLog) && @annotation(controllerLogCopy)", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result, Log controllerLog, LogCopy controllerLogCopy){
        log.info("方法返回值：{}", result);
        log.info("注解描述：{}", controllerLog.value());
        log.info("注解描述：{}", controllerLogCopy.value());
        log.info("方法名：{}", joinPoint.getSignature().getName());

    }




    @Before(value = "@annotation(com.example.proxy.annotation.LogT)")
    public void before(JoinPoint joinPoint){
        log.info("before");
    }


    @After(value = "@annotation(com.example.proxy.annotation.LogT)")
    public void after(JoinPoint joinPoint){
        log.info("After");
    }


    @AfterReturning(pointcut = "@annotation(com.example.proxy.annotation.LogT)")
    public void doAfterReturning2(JoinPoint joinPoint){
        log.info("AfterReturning");
    }

    @Around(value = "@annotation(com.example.proxy.annotation.LogT)")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("around前");
        joinPoint.proceed(joinPoint.getArgs());
        log.info("around后");
    }
}
